#include "Agent/agenttaskbase.h"
#include "Agent/agentprotocol.h"
#include <QDebug>
#include <QTimer>
#include <QUdpSocket>
#include "Agent/agentpush.h"
#include "Agent/getsetfield.h"

AgentTaskBase::AgentTaskBase(QMap <QByteArray,QByteArray> mapIPPortReqPacket,QByteArray packet,QString paramAppIP,
                quint16 paramAppPort,QObject *parent):QObject(parent)
{
    fieldIsSingleShot=true;
    isCreatedSuccessfully=false;
    origPacket=packet;
    fieldPayLoad="";
    fieldComparisonOperator="";
    fieldHoldMilliSeonds=0;
    fieldHoldTimes=1;
    isSNClientValid=false;

    mapOldIPPortWatchReqPacket=mapIPPortReqPacket;

    agentPush=new AgentPush(this);
    connect(agentPush,SIGNAL(sigSendDataToApp(QByteArray,QString,quint16)),
            this,SIGNAL(sigSendDataToApp(QByteArray,QString,quint16)));
    connect(this,SIGNAL(sigNewSubscriber(QByteArray,QByteArray,QByteArray)),
            agentPush,SLOT(newSubscriber(QByteArray,QByteArray,QByteArray)));
    connect(this,SIGNAL(sigPushToApps(QByteArray)),agentPush,
            SLOT(pushToApps(QByteArray)));

    appIP=paramAppIP;
    appPort=paramAppPort;

    agentProtocol=new AgentProtocol(this);
    udpSocketWithServer=new QUdpSocket(this);
    connect(udpSocketWithServer,SIGNAL(readyRead()),this,
            SLOT(slotProcessServerUdpDatagram()));

    //一段时间以后再执行接下来的初始化。那时候，各种信号与槽都已经连接好
    QTimer::singleShot(100,this,SLOT(slotInitBaseClass()));

}

void AgentTaskBase::slotInitBaseClass()
{
    QByteArray packet=origPacket;
    QByteArray baSNLine,baSN;
    baSN=GetSetField::getSN(packet);
    baSNLine="\nSN:"+baSN;

    QList <QByteArray> listBaLines=packet.split('\n');
    QByteArray baOneLine=listBaLines.at(0).simplified();
    QList <QByteArray> listFieldsInOneLine=baOneLine.split(' ');
    listBaLines.removeFirst();
    //在AgentInThread中，已经保证数据包第一行是正确的
    iOTVersionAppPacket=listFieldsInOneLine.at(2);
    fieldMethod=listFieldsInOneLine.at(0);
    fieldURL=listFieldsInOneLine.at(1);

    qint32 posOfTowLine=packet.indexOf("\n\n");
    if(posOfTowLine<0)
    {
        emit sigSendDataToApp(agentProtocol->replyLineBadRequest()+baSNLine+"\n\n"
            "At least One CRLF missing before the payload!(Even if the payload is empty)",
             appIP,appPort);
        deleteLater();
        return;
    }

    while(listBaLines.size()>=3&&(!listBaLines.at(0).isEmpty()))
    {
        baOneLine=listBaLines.at(0).simplified();
        if(!parseOneLine(baOneLine))
        {
            listBaLines.removeFirst();

            continue;
        }

        listBaLines.removeFirst();
    }

    if(listBaLines.size()<2)
    {
        emit sigSendDataToApp(agentProtocol->replyLineBadRequest()+baSNLine+"\n\n"
            "At least One CRLF missing before the payload!",appIP,appPort);
        deleteLater();
        return;
    }

    if(!fieldComparisonOperator.isEmpty()&&fieldComparisonOperator!=">"
            &&fieldComparisonOperator!="=="&&fieldComparisonOperator!="!="
            &&fieldComparisonOperator!="<")
    {
        emit sigSendDataToApp(agentProtocol->replyLineNotImplemented()+baSNLine+"\n\n"
            "Comparison-Operator in this packet is not supported!",appIP,appPort);

        emit sigErrorInfo("Not implemented comparison-operator.\n"
                          "Destroying agent...");
        deleteLater();
        return;
    }
    setPayLoad(getPayLoadFromPacket(packet)); //解析到最后的负载部分

    //通知APP执行成功
    emit sigSendDataToApp(agentProtocol->replyLineOK()
                          +baSNLine+"\n"
            "Host:Agent\n\n",appIP,appPort);

    slotInitDerivedClass();

    if(isCreatedSuccessfully)
    {
        QMapIterator<QByteArray, QByteArray> i(mapOldIPPortWatchReqPacket);
        while (i.hasNext())
        {
            i.next();
            QByteArray ipPort=i.key();
            QList <QByteArray> list=ipPort.split(':');
            if(list.size()==2)
            {
                bool ok;
                slotAgentWatch(i.value(),list.at(0),list.at(1).toUInt(&ok,10));
            }
        }

        /*****发送推送消息.AgentPush类会自动加上正确的SN字段******************/
        QByteArray agentPushFirstLine="AgentPush StateChanged IOT/3.5\n"
                "TaskCreated "+fieldURL+'\n';
        QByteArray agentPushPayLoad=origPacket;
        packetToPush=agentPushFirstLine.append(agentPushPayLoad);
        QTimer::singleShot(100,this,SLOT(slotEmitSigPushToApps()));
    }


}

void AgentTaskBase::slotEmitSigPushToApps()
{
    emit sigPushToApps(packetToPush);
}

QByteArray AgentTaskBase::getPayLoadFromPacket(QByteArray paramPacket)
{
    QByteArray payLoad="";
    qint32 posOfTowLine=paramPacket.indexOf("\n\n");
    if(posOfTowLine>=0)
    {
        payLoad=paramPacket.mid(posOfTowLine+2); //解析到最后的负载部分
    }
    return payLoad;
}

bool AgentTaskBase::parseOneLine(QByteArray baLine)
{
    bool isFormantRight=true;
    QList <QByteArray> listFieldInOneline=baLine.simplified().split(':');
    if(listFieldInOneline.size()!=2)
        return false;
    else
    {
        bool ok;
        QByteArray fieldName=listFieldInOneline.at(0);
        QByteArray fieldData=listFieldInOneline.at(1);
        if(fieldName.toUpper()=="SN")
        {
            fieldSN=fieldData.toLongLong(&ok,10);
            if(!ok)
                return false;
        }
        else if(fieldName.toUpper()=="HOST")
            fieldHost=fieldData;
        else if(fieldName.toUpper()=="SINGLESHOT")
        {
            if(fieldData.toUpper()=="TRUE")
                fieldIsSingleShot=true;
            else
                fieldIsSingleShot=false;
        }
        else if(fieldName.toUpper()=="TRIGGER-DATE")
            fieldTriggerDate=fieldData;
        else if(fieldName.toUpper()=="TRIGGER-TIME")
            fieldTriggerTime=fieldData;
        else if(fieldName.toUpper()=="TIMEOUT-SECONDS")
        {
            fieldTimeOutSeconds=fieldData.toLongLong(&ok,10);
            if(!ok||fieldTimeOutSeconds<1)
                return false;
        }
        else if(fieldName.toUpper()=="HOLD-MILLISECONDS")
        {
            fieldHoldMilliSeonds=fieldData.toLongLong(&ok,10);
            if(!ok||fieldHoldMilliSeonds<1)
                return false;
        }
        else if(fieldName.toUpper()=="HOLD-TIMES")
        {
            fieldHoldTimes=fieldData.toULong(&ok,10);
            if(!ok||fieldHoldTimes<1)
                return false;
        }
        else if(fieldName.toUpper()=="SOURCE-MAC")
            fieldSrcMac=fieldData.toLongLong(&ok,10);
        else if(fieldName.toUpper()=="SOURCE-NODENAME")
            fieldSrcNodeName=fieldData;
        else if(fieldName.toUpper()=="SOURCE-SENSORNAME")
            fieldSrcSensorName=fieldData;
        else if(fieldName.toUpper()=="DEST-MAC")
            fieldDestMac=fieldData.toLongLong(&ok,10);
        else if(fieldName.toUpper()=="DEST-SENSORNAME")
            fieldDestSensorName=fieldData;
        else if(fieldName.toUpper()=="COMPARISON-OPERATOR")
            fieldComparisonOperator=fieldData;
        else if(fieldName.toUpper()=="COMPARED-NUMBER")
        {
            if(fieldData.contains('.')) //浮点数
            {
                fieldComparedNumberDouble=fieldData.toDouble(&ok);
                if(!ok)
                    return false;
                fieldComparedNumberInt=false;
            }
             else //不包含点，可能是浮点数，也可能不是
            {
                fieldComparedNumberInt=fieldData.toLongLong(&ok,10);
                fieldComparedNumberDouble=fieldData.toDouble(&ok);
                if(!ok)
                    return false;
                fieldIsComparedNumberInt=true;
            }
        }
        else
        {
            emit sigSendDataToApp(agentProtocol->replyLineBadRequest()+"\n\n"
                "There is one line without proper format.\n",appIP,appPort);
            isFormantRight=false;
        }

        return isFormantRight;
    }
}

void AgentTaskBase::setPayLoad(QByteArray paramLoad)
{
    fieldPayLoad=paramLoad;
}

void AgentTaskBase::slotAgentGet(QByteArray packet, QString paramAppIP, quint16 paramAppPort)
{
    QByteArray baSNLine,baSN;
    baSN=GetSetField::getSN(packet);
    baSNLine="\nSN:"+baSN;

    //每个AgentTask都会收到AgentGet命令。需要先查看是不是发给自己的
    if(isHit(packet))
    {
        //qint16 posOfFirstN=origPacket.indexOf('\n');
        //if(posOfFirstN>=0)
        {
            QByteArray sendpacket=origPacket;
            //sendpacket.remove(0,posOfFirstN);//保留换行符
            sendpacket.prepend(agentProtocol->replyLineOK()+'\n');

            sendpacket=GetSetField::setSN(sendpacket,baSN);

            emit sigSendDataToApp(sendpacket,paramAppIP,paramAppPort);
        }
    }
}

void AgentTaskBase::slotAgentWatch(QByteArray packet, QString paramAppIP, quint16 paramAppPort)
{
    QByteArray baSNLine,baSN;
    baSN=GetSetField::getSN(packet);
    baSNLine="\nSN:"+baSN;
    //每个AgentTask都会收到AgentWatch命令。需要先查看是不是发给自己的
    if(isHit(packet))
    {
        emit sigNewSubscriber(baSN,paramAppIP.toUtf8()+":"+QByteArray::number(paramAppPort,10),packet);
    }
}

void AgentTaskBase::slotAgentDelete(QByteArray packet, QString paramAppIP, quint16 paramAppPort)
{
    //每个AgentTask都会收到AgentDelete命令。需要先查看是不是发给自己的
    QByteArray baSNLine,baSN;
    baSN=GetSetField::getSN(packet);
    baSNLine="\nSN:"+baSN;
    if(isHit(packet))
    {
        emit sigSendDataToApp(agentProtocol->replyLineOK()+baSNLine+"\n"
                "Host:Agent\n\n"
                "INFO:Agent Deleted successfully",paramAppIP,paramAppPort);
        deleteLater();
    }

}

bool AgentTaskBase::isHit(QByteArray paramPacket)
{
    if(!paramPacket.contains("\n\n"))
        return false;

    QByteArray temp=paramPacket;
    temp.truncate(temp.indexOf("\n\n"));

    QList <QByteArray> listBaLines=temp.split('\n');
    QByteArray baOneLine=listBaLines.at(0).simplified();
    QList <QByteArray> listFieldsInOneLine=baOneLine.split(' ');
    listBaLines.removeFirst();
    //在AgentInThread中，已经保证数据包第一行是正确的
    if(!fieldURL.startsWith(listFieldsInOneLine.at(1)))
        return false;
    while(listBaLines.size()>=1)
    {
        baOneLine=listBaLines.at(0).simplified();
        if(!isOneLineHit(baOneLine))
        {
            return false;
        }

        listBaLines.removeFirst();;
    }
    QByteArray newPayLoad=getPayLoadFromPacket(paramPacket);
    if(!newPayLoad.isEmpty()&&fieldPayLoad!=newPayLoad)
        return false;
    else
        return true;
}
bool AgentTaskBase::isOneLineHit(QByteArray baLine)
{
    QList <QByteArray> listFieldInOneline=baLine.simplified().split(':');
    if(listFieldInOneline.size()!=2) //不符合格式，不作判断
        return true;
    else
    {
        bool ok;
        QByteArray fieldName=listFieldInOneline.at(0);
        QByteArray fieldData=listFieldInOneline.at(1);
        if(fieldName.toUpper()=="SN")
        {
            sNClient=fieldData.toULongLong(&ok,10);//SN不作为比较内容
            isSNClientValid=ok;
            return true;
        }
        else if(fieldName.toUpper()=="HOST")
            return fieldHost.toUpper()==fieldData.toUpper();
        else if(fieldName.toUpper()=="SINGLESHOT")
        {
            if(fieldData.toUpper()=="TRUE")
                return fieldIsSingleShot==true;
            else
                return fieldIsSingleShot==false;
        }
        else if(fieldName.toUpper()=="TRIGGER-DATE")
            return fieldTriggerDate.toUpper()==fieldData.toUpper();
        else if(fieldName.toUpper()=="TRIGGER-TIME")
            return fieldTriggerTime.toUpper()==fieldData.toUpper();


        else if(fieldName.toUpper()=="TIMEOUT-SECONDS")
            return fieldTimeOutSeconds==fieldData.toLongLong(&ok,10);
        else if(fieldName.toUpper()=="HOLD-MILLISECONDS")
            return fieldHoldMilliSeonds==fieldData.toLongLong(&ok,10);
        else if(fieldName.toUpper()=="SOURCE-MAC")
            return fieldSrcMac==fieldData.toLongLong(&ok,10);
        else if(fieldName.toUpper()=="SOURCE-SENSORNAME")
            return fieldSrcSensorName.toUpper()==fieldData.toUpper();
        else if(fieldName.toUpper()=="DEST-MAC")
            return fieldDestMac==fieldData.toLongLong(&ok,10);
        else if(fieldName.toUpper()=="DEST-SENSORNAME")
            return fieldDestSensorName.toUpper()==fieldData.toUpper();
        else if(fieldName.toUpper()=="COMPARISON-OPERATOR")
            return fieldComparisonOperator.toUpper()==fieldData.toUpper();
        else if(fieldName.toUpper()=="COMPARED-NUMBER")
        {
            if(fieldComparedNumberInt==false)
            {
                return fieldComparedNumberDouble==fieldData.toDouble(&ok);
            }
             else
            {
                return fieldComparedNumberInt==fieldData.toLongLong(&ok,10);
            }
        }
        else
            return false; //未识别的限定条件，不作比较
    }
}

bool AgentTaskBase::isComparisonHit(QByteArray baComparingNumber)
{
    if(fieldComparisonOperator.isEmpty())
        return true;

    bool ok;

    if(fieldIsComparedNumberInt)
    {
        qint64 comparingNumber=baComparingNumber.toLongLong(&ok,10);
        if(ok&&compareInt(comparingNumber))
        {
            return true;
        }
        if(!ok)
        {
            double comparingNumber=baComparingNumber.toDouble(&ok);
            if(ok&&compareDouble(comparingNumber))
            {
                return true;
            }
        }
    }
    else
    {
        double comparingNumber=baComparingNumber.toDouble(&ok);
        if(ok&&compareDouble(comparingNumber))
        {
            return true;
        }
        if(!ok)
        {
            qint64 comparingNumber=baComparingNumber.toLongLong(&ok);
            if(ok&&compareInt(comparingNumber))
            {
                return true;
            }
        }
    }
    return false;

}

bool AgentTaskBase::compareDouble(double comparingNumber)
{
    if(fieldComparisonOperator==">")
        return comparingNumber>fieldComparedNumberDouble;
    else if(fieldComparisonOperator=="==")
        return comparingNumber==fieldComparedNumberDouble;
    else if(fieldComparisonOperator=="!=")
        return comparingNumber!=fieldComparedNumberDouble;
    else if(fieldComparisonOperator=="<")
        return comparingNumber<fieldComparedNumberDouble;
    else
        return false;
}

bool AgentTaskBase::compareInt(qint64 comparingNumber)
{
    if(fieldComparisonOperator==">")
        return comparingNumber>fieldComparedNumberInt;
    else if(fieldComparisonOperator=="==")
        return comparingNumber==fieldComparedNumberInt;
    else if(fieldComparisonOperator=="!=")
        return comparingNumber!=fieldComparedNumberInt;
    else if(fieldComparisonOperator=="<")
        return comparingNumber<fieldComparedNumberInt;
    else
        return false;
}

void AgentTaskBase::slotProcessServerUdpDatagram()
{
    QByteArray datagram;
    QHostAddress clientIP;
    quint16 clientPort;
    do{
       datagram.resize(udpSocketWithServer->pendingDatagramSize());
      udpSocketWithServer->readDatagram(datagram.data(),datagram.size(),&clientIP,&clientPort); //读数据包

      if(!datagram.isEmpty())
         analyzeIncomeDatagram(datagram);
    }while (udpSocketWithServer->hasPendingDatagrams());

}

void AgentTaskBase::slotSendPacket(QByteArray packet, QString strIP, quint16 udpPort)
{
    udpSocketWithServer->writeDatagram(packet,(QHostAddress)strIP,udpPort);
}

AgentTaskBase::~AgentTaskBase()
{
    /*****发送推送消息******************/
    if(isCreatedSuccessfully)
    {
        QByteArray agentPushFirstLine="AgentPush StateChanged IOT/3.5\n"
                "TaskDeleted "+fieldURL+'\n';
        QByteArray agentPushPayLoad=origPacket;
        emit sigPushToApps(agentPushFirstLine.append(agentPushPayLoad));
    }
}
